#include <iostream>
#include <fstream>
#include <vector>
#include <opencv2/opencv.hpp>
#include <nlohmann/json.hpp>
#include <curl/curl.h>
#include <stdexcept>
#include <openssl/bio.h>
#include <openssl/evp.h>
#include <openssl/pem.h>

using json = nlohmann::json;

// 坐标点结构体
struct Point {
    int x;
    int y;
};

// 将图片转换为Base64字符串
std::string mat_to_base64(const cv::Mat& mat) {
    std::vector<uchar> buf;
    cv::imencode(".png", mat, buf);
    return std::string(buf.begin(), buf.end());
}

// 发起POST请求的函数
json post_request(const std::string& url, const json& data) {
    CURL *curl;
    CURLcode res;
    std::string readBuffer;

    curl = curl_easy_init();
    if(curl) {
        // 设置POST数据
        struct curl_slist *headers = nullptr;
        headers = curl_slist_append(headers, "Content-Type: application/json");
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
        curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
        curl_easy_setopt(curl, CURLOPT_POST, 1L);
        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.dump().c_str());
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, [](char *ptr, size_t size, size_t nmemb, std::string *data) {
            data->append(ptr, size * nmemb);
            return size * nmemb;
        });
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);

        res = curl_easy_perform(curl);
        if(res != CURLE_OK) {
            std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl;
            curl_easy_cleanup(curl);
            throw std::runtime_error("Failed to perform POST request");
        }

        curl_easy_cleanup(curl);

        // 解析返回的JSON
        try {
            return json::parse(readBuffer);
        } catch (const json::parse_error& e) {
            std::cerr << "Failed to parse response JSON: " << e.what() << std::endl;
            throw;
        }
    } else {
        throw std::runtime_error("Failed to initialize CURL");
    }
}

// 处理返回的JSON
void handle_response(const json& response) {
    if(response.contains("code")) {
        int code = response["code"].get<int>();
        if(code == 200) {
            std::cout << "Success: Code 200" << std::endl;
            // 处理200逻辑
        } else if(code == 201) {
            std::cout << "Success: Code 201" << std::endl;
            // 处理201逻辑
        } else {
            std::cout << "Unknown code: " << code << std::endl;
        }
    } else {
        std::cerr << "Response does not contain 'code' field" << std::endl;
    }
}

// 解析JSON并裁切图片
json process_subjects(const std::string& json_path, 
                     const std::string& image_path,
                     const std::string& output_dir) {
    // 读取JSON文件
    std::ifstream f(json_path);
    json body_data = json::parse(f);
    json resp,json_list;
    // 创建输出目录
    system(("mkdir -p " + output_dir).c_str());

    // 加载原始图片
    cv::Mat img = cv::imread(image_path);
    if(img.empty()) {
        std::cerr << "Error loading image: " << image_path << std::endl;
        return resp;
    }

    // 遍历所有题目
    int subject_count = 0;
    for (auto& page : body_data["pages"]) {
        for (auto& subject : page["subjects"]) {
            for (auto& content : subject["content_list_info"]) {
                // 提取坐标点
                std::vector<Point> points;
                for (auto& p : content["pos"]) {
                    points.push_back({
                        p["x"].get<int>(),
                        p["y"].get<int>()
                    });
                }

                // 计算裁切区域
                if(points.size() != 4) {
                    std::cerr << "Invalid points count: " << points.size() << std::endl;
                    continue;
                }

                // 找到边界坐标
                int x_min = points[0].x, x_max = points[0].x;
                int y_min = points[0].y, y_max = points[0].y;
                for (const auto& p : points) {
                    x_min = std::min(x_min, p.x);
                    x_max = std::max(x_max, p.x);
                    y_min = std::min(y_min, p.y);
                    y_max = std::max(y_max, p.y);
                }

                // 边界检查
                x_min = std::max(0, x_min);
                x_max = std::min(img.cols-1, x_max);
                y_min = std::max(0, y_min);
                y_max = std::min(img.rows-1, y_max);

                // 执行裁切
                if(x_max > x_min && y_max > y_min) {
                    cv::Rect roi(x_min, y_min, x_max - x_min, y_max - y_min);
                    cv::Mat sub_img = img(roi);
                    
                    // 保存结果
                    std::string output_path = output_dir + "/subject_" + 
                                            std::to_string(++subject_count) + 
                                            ".png";
                    cv::imwrite(output_path, sub_img);

                    // 将图片转换为Base64
                    std::string base64_img = mat_to_base64(sub_img);

                    // 向API发送请求，检查是否有这道题
                    try {
                        json request_data = {
                            {"content", content["text"]},
                            {"picture", base64_img}
                        };
                        json response = post_request("https://api.example.com/check_subject", request_data);
                        json_list.push_back(response);
                        //handle_response(response);
                    } catch (const std::exception& e) {
                        std::cerr << "Error during API request: " << e.what() << std::endl;
                    }
                }
            }
        }
    }
    
    resp["json_list"]=json_list;
    std::cout << "Processed " << subject_count << " subjects" << std::endl;
    return resp;
}

int main(int argc, char** argv) {
    if(argc != 5) {
        std::cout << "Usage: " << argv[0] 
                  << " <input.json> <input_image> <output_dir>" 
                  << std::endl;
        return 1;
    }

    try {
        json resp = process_subjects(argv[1], argv[2], argv[3]);
        std::string file_path = std::string(argv[4])+"_response.json";
        std::ofstream file(file_path);
        if (file.is_open()) {
        file << resp.dump(4); // 使用 4 个空格进行格式化
        file.close();
        std::cout << "JSON data has been saved to " << file_path << std::endl;
    	} else {
            std::cerr << "Unable to open file: " << file_path << std::endl;
    	}

    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
        return 1;
    }
    return 0;
}

//g++ cut_pic_from_photo.cpp -o cut_pic_from_photo `pkg-config --cflags --libs opencv4` -lcurl -lssl -lcrypto
//config instruction
